#ifndef __BYTEARRAY_H__
#define __BYTRARRAY_H__

#include<memory>
#include<string>
#include<stdint.h>
#include<vector>
#include <sys/uio.h>     //iovec
#include"endian.h"

namespace sylar{
    
class ByteArray{
public:
    using ptr = std::shared_ptr<ByteArray>;

    // 数据结构做成链表的形式
    struct Node{
        Node(size_t s);
        Node();
        ~Node();

        char* ptr;
        Node* next;   //下一块内存地址
        size_t size;  //当前内存块大小
    };

    ByteArray(size_t base_size = 4096);
    ~ByteArray();

    //写入固定长度int8_t类型的数据
    //m_position += sizeof(value)
    void writeFint8  (int8_t value);
    void writeFuint8 (uint8_t value);

    //写入固定长度int16_t类型的数据(大端/小端)
    //m_position += sizeof(value)
    void writeFint16 (int16_t value);
    void writeFuint16(uint16_t value);

    //写入固定长度int32_t类型的数据(大端/小端)
    //m_position += sizeof(value)
    void writeFint32 (int32_t value);
    void writeFuint32(uint32_t value);

    //写入固定长度int64_t类型的数据(大端/小端)
    //m_position += sizeof(value)
    
    void writeFint64 (int64_t value);
    void writeFuint64(uint64_t value);

    //写入有符号Varint32类型的数据， 没有F是可变长度压缩
    //m_position += 实际占用内存(1 ~ 5) 
    void writeInt32  (int32_t value);
    void writeUint32 (uint32_t value);

    //写入有符号Varint64类型的数据
    //m_position += 实际占用内存(1 ~ 10)
    void writeInt64  (int64_t value);
    void writeUint64 (uint64_t value);

    //写入float类型的数据
    //m_position += sizeof(value)  
    void writeFloat  (float value);
    void writeDouble (double value);

    //写入std::string类型的数据,用uint16_t，uint32, uint64作为长度类型
    //m_position += 2 + value.size()
    void writeStringF16(const std::string& value);
    void writeStringF32(const std::string& value);
    void writeStringF64(const std::string& value);

    //写入std::string类型的数据,用无符号Varint64作为长度类型
    //m_position += Varint64长度 + value.size()
    void writeStringVint(const std::string& value);

    //写入std::string类型的数据,无长度
    //m_position += value.size()
    void writeStringWithoutLength(const std::string& value);


    //读取int8_t类型的数据
    //getReadSize() >= sizeof(int8_t)
    //m_position += sizeof(int8_t);
    //如果getReadSize() < sizeof(int8_t) 抛出 std::out_of_range
    int8_t   readFint8();
    uint8_t  readFuint8();
    int16_t  readFint16();
    uint16_t readFuint16();
    int32_t  readFint32();
    uint32_t readFuint32();
    int64_t  readFint64();
    uint64_t readFuint64();

    //读取有符号Varint32类型的数据
    //getReadSize() >= 有符号Varint32实际占用内存
    //m_position += 有符号Varint32实际占用内存
    //如果getReadSize() < 有符号Varint32实际占用内存 抛出 std::out_of_range
    int32_t  readInt32();

    //读取无符号Varint32类型的数据
    //getReadSize() >= 无符号Varint32实际占用内存
    //m_position += 无符号Varint32实际占用内存
    //如果getReadSize() < 无符号Varint32实际占用内存 抛出 std::out_of_range
    uint32_t readUint32();
    int64_t  readInt64();
    uint64_t readUint64();

    //读取float类型的数据
    //getReadSize() >= sizeof(float)
    //m_position += sizeof(float);
    //如果getReadSize() < sizeof(float) 抛出 std::out_of_range
    float    readFloat();

    //读取double类型的数据
    //getReadSize() >= sizeof(double)
    //m_position += sizeof(double);
    //如果getReadSize() < sizeof(double) 抛出 std::out_of_range
    double   readDouble();

    //读取std::string类型的数据,用uint16_t作为长度
    //getReadSize() >= sizeof(uint16_t) + size
    //m_position += sizeof(uint16_t) + size;
    //如果getReadSize() < sizeof(uint16_t) + size 抛出 std::out_of_range
    std::string readStringF16();
    std::string readStringF32();
    std::string readStringF64();

    //读取std::string类型的数据,用无符号Varint64作为长度
    //getReadSize() >= 无符号Varint64实际大小 + size
    //m_position += 无符号Varint64实际大小 + size;
    //如果getReadSize() < 无符号Varint64实际大小 + size 抛出 std::out_of_range
    std::string readStringVint();

    /**
     * @brief 清空bytearray
     * 
     */
    void clear();

    /**
     * @brief 写入size长度
     * m_position += size, 如果m_position > m_size 则 m_size = m_position
     * @param buf 内存缓存指针
     * @param size 
     */
    void write(const void* buf, size_t size);

    /**
     * @brief 读取size长度的数据
     * m_position += size, 如果m_position > m_size 则 m_size = m_position
     * 如果getReadSize() < size 则抛出 std::out_of_range
     * @param buf 
     * @param size 
     */
    void read(void* buf, size_t size);

    /**
     * @brief 读取position位置size长度的数据
     * 如果 (m_size - position) < size 则抛出 std::out_of_range
     * @param buf 
     * @param size 
     * @param position 
     */
    void read(void* buf, size_t size, size_t position) const;

    /**
     * @brief 返回ByteArray当前位置
     * 
     * @return size_t 
     */
    size_t getPosition() const { return m_position;}

    /**
     * @brief 设置ByteArray当前位置
     * 如果m_position > m_size 则 m_size = m_position
     * 如果m_position > m_capacity 则抛出 std::out_of_range
     * @param v 
     */
    void setPosition(size_t v);

    /**
     * @brief 把ByteArray的数据写入到文件中name 文件名
     * 如果数据有问题可以写到文件里看一看
     * @param name 
     * @return true 
     * @return false 
     */
    bool writeToFile(const std::string& name) const;

    //从文件中读取数据 name 文件名
    bool readFromFile(const std::string& name);

    // 返回内存块的大小
    size_t getBaseSize() const { return m_baseSize;}

    // 返回可读取数据大小
    size_t getReadSize() const { return m_size - m_position;}

    //是否是小端
    bool isLittleEndian() const;

    // 设置是否为小端
    void setIsLittleEndian(bool val);

    // 将ByteArray里面的数据[m_position, m_size)转成std::string
    std::string toString() const;

    //将ByteArray里面的数据[m_position, m_size)转成16进制的std::string(格式:FF FF FF)
    std::string toHexString() const;

    /**
     * @brief 获取可读取的缓存,保存成iovec数组
     * 
     * @param buffers buffers 保存可读取数据的iovec数组
     * @param len 读取数据的长度,如果len > getReadSize() 则 len = getReadSize()
     * @return uint64_t 实际数据的长度
     */
    uint64_t getReadBuffers(std::vector<iovec>& buffers, uint64_t len = ~0ull) const;

    /**
     * @brief 获取可读取的缓存,保存成iovec数组,从position位置开始
     * 
     * @param buffers 保存可读取数据的iovec数组
     * @param len 读取数据的长度,如果len > getReadSize() 则 len = getReadSize()
     * @param position 读取数据的位置
     * @return uint64_t 实际数据的长度
     */
    uint64_t getReadBuffers(std::vector<iovec>& buffers, uint64_t len, uint64_t position) const;

    /**
     * @brief 获取可写入的缓存,保存成iovec数组
     * 如果(m_position + len) > m_capacity 则 m_capacity扩容N个节点以容纳len长度
     * @param buffers 保存可写入的内存的iovec数组
     * @param len 写入的长度
     * @return uint64_t 实际的长度
     */
    uint64_t getWriteBuffers(std::vector<iovec>& buffers, uint64_t len);

    // 返回数据的长度
    size_t getSize() const { return m_size;}
private:

    //扩容ByteArray,使其可以容纳size个数据(如果原本可以可以容纳,则不扩容)
    void addCapacity(size_t size);
    // 获取当前的可写入容量
    size_t getCapacity() const { return m_capacity - m_position;}

private:
    /// 内存块的大小
    size_t m_baseSize;
    /// 当前操作位置(相对于链表)
    size_t m_position;
    /// 当前的总容量
    size_t m_capacity;
    /// 当前数据的大小
    size_t m_size;
    /// 字节序,默认大端
    int8_t m_endian;
    /// 第一个内存块指针
    Node* m_root;
    /// 当前操作的内存块指针
    Node* m_cur;

};
}



#endif